package com.ruoyi.myutils;


import lombok.extern.slf4j.Slf4j;
import org.geotools.data.FileDataStore;
import org.geotools.data.FileDataStoreFinder;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.CRS;
import org.geotools.util.factory.Hints;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryCollection;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.io.WKTWriter;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;


public class ShpToWktConverter {
    private static final Logger log = Logger.getLogger(ShpToWktConverter.class.getName());
    private static final WKTWriter WKT_WRITER = new WKTWriter(3); // 3位小数精度

    /**
     * 将上传的SHP文件转换为WKT格式
     * @param shpFiles 上传的SHP文件及相关文件
     * @return WKT格式字符串
     */
    public static String multipartFileShp2Wkt(MultipartFile[] shpFiles) {
        List<Geometry> geometries = new ArrayList<>();
        Path tempDir = null;

        try {
            tempDir = createTempDirectory();
            log.info("临时目录创建成功: {}");

            String shpFilePath = saveUploadedFiles(shpFiles, tempDir);
            if (shpFilePath == null) {
                log.info("未找到SHP文件");
                return null;
            }

            geometries = shpToGeometries(shpFilePath);
            log.info("成功转换 {} 个几何对象");

        } catch (Exception e) {
            log.log(Level.SEVERE, "处理SHP文件时发生错误", e);
        } finally {
            deleteTempDirectory(tempDir);
        }

        if (!geometries.isEmpty()) {
            // 如果只有一个几何对象，直接转换为WKT
            if (geometries.size() == 1) {
                return geometryToWkt(geometries.get(0));
            }
            // 多个几何对象，创建GeometryCollection
            GeometryFactory factory = geometries.get(0).getFactory();
            GeometryCollection collection = factory.createGeometryCollection(
                    geometries.toArray(new Geometry[0]));
            return geometryToWkt(collection);
        }

        return null;
    }

    /**
     * 将Geometry对象转换为WKT格式
     * @param geometry 几何对象
     * @return WKT字符串
     */
    private static String geometryToWkt(Geometry geometry) {
        if (geometry == null) {
            return null;
        }
        return WKT_WRITER.write(geometry);
    }

    /**
     * 从SHP文件中读取几何对象
     * @param filePath SHP文件路径
     * @return 几何对象列表
     */
    private static List<Geometry> shpToGeometries(String filePath) {
        List<Geometry> geometries = new ArrayList<>();
        FileDataStore store = null;
        FeatureIterator<SimpleFeature> features = null;

        try {
            // 强制使用XY坐标轴顺序
            Hints.putSystemDefault(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE);

            store = FileDataStoreFinder.getDataStore(new File(filePath));
            SimpleFeatureSource featureSource = store.getFeatureSource();
            SimpleFeatureCollection featureCollection = featureSource.getFeatures();
            features = featureCollection.features();

            // 获取源CRS并转换到EPSG:4326
            CoordinateReferenceSystem sourceCRS = getSourceCRS(store);
            CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:4326");
            MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS, true);

            while (features.hasNext()) {
                SimpleFeature feature = features.next();
                Geometry geometry = (Geometry) feature.getDefaultGeometry();
                if (geometry != null) {
                    // 坐标转换
                    Geometry transformedGeometry = JTS.transform(geometry, transform);
                    geometries.add(transformedGeometry);
                }
            }
        } catch (Exception e) {
            log.log(Level.SEVERE, "处理SHP文件时发生错误", e);
        } finally {
            closeQuietly(features);
            disposeQuietly(store);
        }

        return geometries;
    }

    /**
     * 获取数据源的坐标参考系统
     */
    private static CoordinateReferenceSystem getSourceCRS(FileDataStore store) throws Exception {
        SimpleFeatureType schema = store.getSchema();
        CoordinateReferenceSystem crs = schema.getCoordinateReferenceSystem();

        // 如果未找到CRS，尝试从.prj文件获取或默认使用WGS84
        if (crs == null) {
            log.warning("未找到SHP文件的CRS，默认使用EPSG:4326");
            return CRS.decode("EPSG:4326");
        }
        return crs;
    }

    /**
     * 创建临时目录
     */
    private static Path createTempDirectory() throws IOException {
        return Files.createTempDirectory("shp_conversion_");
    }

    /**
     * 保存上传的文件到临时目录
     */
    private static String saveUploadedFiles(MultipartFile[] files, Path tempDir) {
        String shpFilePath = null;

        for (MultipartFile file : files) {
            if (file.isEmpty()) {
                continue;
            }

            try {
                String fileName = file.getOriginalFilename();
                if (fileName == null) {
                    continue;
                }

                Path filePath = tempDir.resolve(fileName);
                file.transferTo(filePath.toFile());

                // 记录SHP文件路径
                if (fileName.toLowerCase().endsWith(".shp")) {
                    shpFilePath = filePath.toString();
                }
            } catch (IOException e) {
                log.log(Level.SEVERE, "保存上传文件时发生错误", e);
            }
        }

        return shpFilePath;
    }

    /**
     * 删除临时目录
     */
    private static void deleteTempDirectory(Path tempDir) {
        if (tempDir != null) {
            try {
                // 递归删除目录及其内容
                Files.walk(tempDir)
                        .sorted(java.util.Comparator.reverseOrder())
                        .map(java.nio.file.Path::toFile)
                        .forEach(java.io.File::delete);
                log.info("临时目录已删除: {}");
            } catch (IOException e) {
                log.log(Level.SEVERE, "删除临时目录时发生错误", e);
            }
        }
    }

    /**
     * 安静地关闭FeatureIterator
     */
    private static void closeQuietly(FeatureIterator<?> iterator) {
        if (iterator != null) {
            try {
                iterator.close();
            } catch (Exception e) {
                // 忽略异常
            }
        }
    }

    /**
     * 安静地释放DataStore资源
     */
    private static void disposeQuietly(FileDataStore store) {
        if (store != null) {
            try {
                store.dispose();
            } catch (Exception e) {
                // 忽略异常
            }
        }
    }
}
